#!/usr/bin/env python
# -*- coding: utf-8 -*-
#===============================================================================
# Copyright 2011 zod.yslin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# 
# Author: zod.yslin
# Email: 
# File Name: handle.py
# Description: 
#   How to catch exception in python with except.
# Edit History: 
#   2011-10-24    File created.
#===============================================================================
import sys

try:
    fout = open('myfile.txt', 'w')
    fout.write("1")
    fout.close()
    fin = open('myfile.txt', 'r')
    s = fin.readline()
    i = int(s.strip())
    print("int is ", i)
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
else:
    """
    The use of the else clause is better than adding additional code to the try 
    clause because it avoids accidentally catching an exception that wasn’t raised by
    the code being protected by the try ... except statement.
    只要沒有match任何一個except就會執行這段程式碼
    """
    print 'has', len(fin.readlines()), 'lines'
    fin.close()


try:
    """
    The except clause may specify a variable after the exception name (or tuple).
    The variable is bound to an exception instance with the arguments stored in instance.args.
    For convenience, the exception instance defines __str__() so the arguments can
    be printed directly without having to reference .args.
    """
    raise Exception('spam', 'eggs')
except Exception as inst:
    print type(inst)     # the exception instance
    print inst.args      # arguments stored in .args
    print inst           # __str__ allows args to printed directly
    x, y = inst          # __getitem__ allows args to be unpacked directly
    print 'x =', x
    print 'y =', y


def this_fails():
    x = 1/0

try:
    """
    Exception handlers don’t just handle exceptions if they occur immediately in the try clause, 
    but also if they occur inside functions that are called (even indirectly) in the try clause.
    """
    this_fails()
except ZeroDivisionError as detail:
    print 'Handling run-time error:', detail

try:
    raise KeyboardInterrupt
except:
    print 'catch exception'
finally:
    """
    The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances.
    """
    print 'Goodbye, world!'


# Defining Clean-up Actions
def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print "division by zero!"
    else:
        print "result is", result
    finally:
        """
        A finally clause is always executed before leaving the try statement,
        whether an exception has occurred or not. 
        When an exception has occurred in the try clause and has not been handled 
        by an except clause (or it has occurred in a except or else clause), 
        it is re-raised after the finally clause has been executed.
        """
        print "executing finally clause"
divide(1, 2)
divide(1, 0)
#divide("2", "1") # re-raise TypeError

# Predefined Clean-up Actions
"""
Some objects define standard clean-up actions to be undertaken when the object is no longer needed,
regardless of whether or not the operation using the object succeeded or failed.
"""

#The problem with this code is that it leaves the file open for an indeterminate amount of time after the code has finished executing.
#This is not an issue in simple scripts, but can be a problem for larger applications. 
for line in open("myfile.txt"):
    print line

#The with statement allows objects like files to be used in a way that ensures they are always cleaned up promptly and correctly.
with open("myfile.txt") as f:
    for line in f:
        print line
#After the statement is executed, the file f is always closed, even if a problem was encountered while processing the lines.
#Other objects which provide predefined clean-up actions will indicate this in their documentation.
